#include "Shell.h"

Shell::Shell(System* sys)
{
	m_system = sys;
	m_shell = m_system->createThread(terminal, this);
	m_system->startAll();
}

Shell::~Shell(void)
{
}

/***************************************************
*	assuming configuration will be used first & once
****************************************************/
void* Shell::terminal(void *arg)
{
	Shell* shell = (Shell*)arg;
	
	bool exit = false;
	int junkMail = 0;

	cout << "Welcome to our nice Shell!" << endl;
	cout << "cmd: ";
	cout.flush();
	while(!exit)
	{

		char buffer[MAXLENGTH];
		int count = read(0,buffer,MAXLENGTH);
		
		buffer[count-1] = 0;
		//translate buffer into string for manipulation
		string input(buffer);

		//get first command
		string cmd = input.substr(0,input.find_first_of(" ",0));
		//cut the first command from input
		input = input.substr(input.find_first_of(" ",0)+1,input.size() - cmd.size());

		bool validCmd = true;
		//CreateNet  Filename
		if(!cmd.compare("CreateNet"))
		{
			string arg0 = input.substr(0,input.find_first_of(" ",0));
			input = input.substr(input.find_first_of(" ",0)+1,input.size() - arg0.size());
			if (arg0.compare("")==0 || arg0.compare(" ")==0 || arg0.compare("\n")==0){
				validCmd = false;	
			}
			if (validCmd){
				shell->m_system->config(arg0.c_str());
				//shell->m_system->startTimer();
				shell->m_system->addShellsMailbox(self()->getID());
				shell->waitForMail(junkMail);
				junkMail = shell->m_system->getNumOfNodes() - 1;
				shell->m_system->stopTimer();
			}
			else{
				printf("USAGE: CreateNet <filename>\n");
			}
		}
		/*
		if(!cmd.compare("x"))
		{
			shell->m_system->config("config.ini");
			shell->m_system->startTimer();
			shell->m_system->addShellsMailbox(self()->getID());
			shell->waitForMail(junkMail);
			junkMail = shell->m_system->getNumOfNodes() - 1;
			shell->m_system->stopTimer();
		}*/
		//CrashNode NodeId
		else if(!cmd.compare("CrashNode"))
		{
			string arg0 = input.substr(0,input.find_first_of(" ",0));
			input = input.substr(input.find_first_of(" ",0)+1,input.size() - arg0.size());
			if (arg0.compare("")==0 || arg0.compare(" ")==0 || arg0.compare("\n")==0){
				validCmd = false;	
			}
			if (validCmd){
				if(!shell->m_system->crashNode(atoi(arg0.c_str())))
					printf("Node %s is suspended and can't crash\n", arg0.c_str());
			}
			else{
				printf("USAGE: CrashNode <NodeId>\n");
			}
		}
		//ReviveNode NodeId
		else if(!cmd.compare("ReviveNode"))
		{
			string arg0 = input.substr(0,input.find_first_of(" ",0));
			input = input.substr(input.find_first_of(" ",0)+1,input.size() - arg0.size());
			if (arg0.compare("")==0 || arg0.compare(" ")==0 || arg0.compare("\n")==0){
				validCmd = false;	
			}
			if (validCmd)
			{
				if(!shell->m_system->reviveNode(atoi(arg0.c_str())))
				{
					printf("Node %s isn't suspended and can't revive\n", arg0.c_str());
				}
				else
				{
					shell->waitForMail(junkMail);
					junkMail=0;
					shell->m_system->stopTimer();
				}
			}
			else{
				printf("USAGE: ReviveNode <NodeId>\n");
			}
		}
		//SetNodeClock NodeId newClock
		else if(!cmd.compare("SetNodeClock"))
		{
			string arg0 = input.substr(0,input.find_first_of(" ",0));
			input = input.substr(input.find_first_of(" ",0)+1,input.size() - arg0.size());
			if (arg0.compare("")==0 || arg0.compare(" ")==0 || arg0.compare("\n")==0){
				validCmd = false;	
			}
			string arg1 =  input.substr(0,input.find_first_of(" ",0));
			input = input.substr(input.find_first_of(" ",0)+1,input.size() - arg1.size());
			if (arg1.compare("")==0 || arg1.compare(" ")==0 || arg1.compare("\n")==0){
				validCmd = false;	
			}
			if (validCmd){
				shell->m_system->setNodeClock(atoi(arg0.c_str()), atoi(arg1.c_str()));
				shell->waitForMail(junkMail);
				junkMail=0;
				shell->m_system->stopTimer();
			}
			else{
				printf("USAGE: SetNodeClock <NodeId> <newClock>\n");
			}
		}
		//SendMeYourClock NodeId
		else if(!cmd.compare("SendMeYourClock"))
		{
			string arg0 = input.substr(0,input.find_first_of(" ",0));
			input = input.substr(input.find_first_of(" ",0)+1,input.size() - arg0.size());
			if (arg0.compare("")==0 || arg0.compare(" ")==0 || arg0.compare("\n")==0){
				validCmd = false;	
			}
			if (validCmd){
				shell->m_system->sendNodeClock(atoi(arg0.c_str()));
				shell->waitForMail(junkMail);
				junkMail=0;
			}
			else{
				printf("USAGE: SendMeYourClock <NodeId>\n");
			}
		}
		//KillAll
		else if(!cmd.compare("KillAll"))
		{
			if (validCmd){
				junkMail = 0;
				shell->m_system->killAll();
			}
			else{
				printf("USAGE: KillAll\n");
			}
		}
		//Time
		else if(!cmd.compare("Time"))
		{
			string arg0 = input.substr(0,input.find_first_of(" ",0));
			//Time i
			if(arg0 != ""){
				input = input.substr(input.find_first_of(" ",0)+1,input.size() - arg0.size());
				if (arg0.compare("")==0 || arg0.compare(" ")==0 || arg0.compare("\n")==0){
					validCmd = false;	
				}
				if (validCmd){
					printf("%s's time: %d\n", arg0.c_str(), shell->m_system->sendNodeTime(atoi(arg0.c_str())));
				}
				else{
					printf("USAGE: Time <i>\n");
				}
			}
			else{
				if (validCmd){
					printf("Total time: %d\n", shell->m_system->getTotalTime());
				}
				else{
					printf("USAGE: Time\n");
				}
			}
		}
		//Max_Length
		else if(!cmd.compare("Max_Length"))
		{
			string arg0 = input.substr(0,input.find_first_of(" ",0));
			//Max_Length i
			if(arg0 != ""){
				input = input.substr(input.find_first_of(" ",0)+1,input.size() - arg0.size());
				if (arg0.compare("")==0 || arg0.compare(" ")==0 || arg0.compare("\n")==0){
					validCmd = false;	
				}
				if (validCmd){
					printf("%s's Max Length: %d\n", arg0.c_str(), shell->m_system->getInboxMaxLength(atoi(arg0.c_str())));
				}
				else{
					printf("USAGE: Max_Length <i>\n");
				}
			}
			else{
				if (validCmd){
					printf("Max Length: %d\n", shell->m_system->getMaxLength());
				}
				else{
					printf("USAGE: Max_Length\n");
				}
			}
		}
		//Number_Of_Steps
		else if(!cmd.compare("Number_Of_Steps"))
		{
			if (validCmd){
				printf("Number Of Steps: %d\n", shell->m_system->getNumOfSteps());
			}
			else{
				printf("USAGE: Number_Of_Steps\n");
			}
		}
		//Exit
		else if(!cmd.compare("Exit"))
		{
			if (validCmd){
				exit = true;
				//shell->m_system->stop();
				printf("Bye...Bye...!\n");
			}
			else{
				printf("USAGE: Exit\n");
			}
		}
		else
		{
			printf("Wrong Command - Try again...\n");
		}

		if(!exit)
		{
			cout << "cmd: ";
			cout.flush();
		}
	}
	
}

void Shell::waitForMail(int howManyMsgs)
{
	for(int i=0 ; i<howManyMsgs ; i++)
	{
		delete m_system->recieve(self()->getID());
	}
	Message* msg = m_system->recieve(self()->getID());
	msg->print();
	m_system->m_numOfSteps = msg->m_timeSteps;
	delete msg;
}

int Shell::getTimeRequest()
{
	return 10 + m_system->getMailboxSize(m_shell->getID());
}

